package com.yuanmei.model;

import android.annotation.SuppressLint;
import android.util.Log;

import com.yuanmei.charts.RealTimeTickChartDataSet;
import com.yuanmei.common.Utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import io.realm.Sort;

public class StockItem implements Comparable<StockItem> {
    private final static String TAG = StockItem.class.getName();
    private String mName;
    private String mCode;
    private String mMatchDetail;
    private String mFinStatements;
    private TdxStockInfo mStockInfo;
    private float mMa20Volume;
    private float mMa5Volume;
    private float mLastHistoryTradeVolume;
    private int mKeyCode;
    private String mNetEaseCode;
    private final Object mTodayQuoteLock = new Object();
    private TodayQuote mTodayQuote;
    private final Object mTsChartDataLock = new Object();
    private RealTimeTickChartDataSet mTodayMinuteTickData = null;
    public enum ItemType {
        STOCK,
        INDEX,
    }

    private ItemType mItemType;

    private String getNeCodeByStockCode(String code) {
        String neCode;
        if (code.startsWith("0")) {
            neCode = "1" + code;
        } else if (code.startsWith("3")) {
            neCode = "1" + code;
        } else {
            neCode = "0" + code;
        }
        return neCode;
    }

    public static String getNeCodeByMarketIndexCode(String code) {
        String neCode;
        if (code.startsWith("39")) {
            neCode = "1" + code;
        } else {
            neCode = "0" + code;
        }
        return neCode;
    }

    private void rebuildVolumeParams() {
        RealmConfiguration stockRealmConfig = new RealmConfiguration.Builder()
                .name(Utils.getDayRealmFile(mNetEaseCode))
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(stockRealmConfig);
        RealmResults<HistoryDayQuote> results = realm.where(HistoryDayQuote.class)
                .sort("date", Sort.ASCENDING).findAll();
        mLastHistoryTradeVolume = 0;

        mMa5Volume = 0;
        mMa20Volume = 0;
        if (results.size() > 0) {
            double totalVolume = 0;
            int sumCounts = 0;
            for (int i = results.size() - 1; i >= 0; i--) {
                HistoryDayQuote quote = results.get(i);
                if (quote != null) {
                    if (mLastHistoryTradeVolume == 0) {
                        Date qd = Utils.getDateFromIDate(quote.getDate());
                        Date now = new Date();
                        if (now.after(qd)) {
                            mLastHistoryTradeVolume = quote.getQuoteVolume();
                        }
                    }

                    totalVolume += quote.getVolume();
                    sumCounts += 1;
                    if (sumCounts == 5) {
                        mMa5Volume = (float) (totalVolume / sumCounts);
                    } else if (sumCounts >= 20) {
                        mMa20Volume = (float) (totalVolume / sumCounts);
                        break;
                    }
                }
            }
            if (mMa5Volume == 0) {
                mMa5Volume = (float) (totalVolume / sumCounts);
            }
            if (mMa20Volume == 0) {
                mMa20Volume = (float) (totalVolume / sumCounts);
            }
        }
        realm.close();
    }

    //    for add pre-defined market index
    public StockItem(String name, String code, boolean isMarketIndex) {
        mName = name;
        mCode = code;
        mMatchDetail = "--";
        mFinStatements =  "--";
        mStockInfo = null;

        if (!isMarketIndex) {
            mNetEaseCode = getNeCodeByStockCode(code);
            mItemType = ItemType.STOCK;
        } else {
            mNetEaseCode = getNeCodeByMarketIndexCode(code);
            mItemType = ItemType.INDEX;
        }

        mKeyCode = 0x80000000 + Integer.valueOf(mNetEaseCode);
        if (!Utils.isMainThread()) {
            updateTodayQuoteLocked();
        }
    }

    // for not from pattern match results
    public StockItem(String name, String code, TdxStockInfo stock_info, boolean isMarketIndex) {
        mName = name;
        mCode = code;
        mMatchDetail = "--";
        mFinStatements =  "--";
        mStockInfo = stock_info;

        if (!isMarketIndex) {
            mNetEaseCode = getNeCodeByStockCode(code);
            mItemType = ItemType.STOCK;
        } else {
            mNetEaseCode = getNeCodeByMarketIndexCode(code);
            mItemType = ItemType.INDEX;
        }

        mKeyCode = 0x80000000 + Integer.valueOf(mNetEaseCode);
        if (!Utils.isMainThread()) {
            updateTodayQuoteLocked();
        }
    }

    public StockItem(String name, String code, String match_detail, String fin_statements,
                     TdxStockInfo stock_info, boolean isMarketIndex) {
        mName = name;
        mCode = code;
        mMatchDetail = match_detail;
        mFinStatements = fin_statements;
        mStockInfo = stock_info;

        if (!isMarketIndex) {
            mNetEaseCode = getNeCodeByStockCode(code);
            mItemType = ItemType.STOCK;
        } else {
            mNetEaseCode = getNeCodeByMarketIndexCode(code);
            mItemType = ItemType.INDEX;
        }

        mKeyCode = 0x80000000 + Integer.valueOf(mNetEaseCode);
        if (!Utils.isMainThread()) {
            updateTodayQuoteLocked();
        }
    }

    public boolean isMarketIndex() {
        return (mItemType == ItemType.INDEX);
    }

    public String netEaseCode() {
        return mNetEaseCode;
    }

    public String code() {
        return mCode;
    }

    public String name() {
        return mName;
    }

    public String getMatchDetail() {
        return mMatchDetail;
    }

    public String getIndustryInfo() {
        if (isMarketIndex()) {
            return "指数";
        }
        if(mStockInfo == null) {
            return "无板块";
        }

        return mStockInfo.getIndustry();
    }


    public String getFinancialStatements() {
        return mFinStatements;
    }

    @SuppressLint("DefaultLocale")
    public String getFinanceInfo() {
        if (mStockInfo == null)
            return "NULL";

        float netAssetsOperatingProfitRate =
                (mStockInfo.getOperatingProfit() * 100.0f) / mStockInfo.getNetAssets();
        String fin_info = "地区:" + mStockInfo.getArea()
                + ",行业:" + mStockInfo.getIndustry()
                + ",上市日期:" + mStockInfo.getTimeToMarket()
                + ",财务更新:" + mStockInfo.getFinancialUpdate() + "\n";
        fin_info += "总股本:" + Utils.amountToShortUnit(mStockInfo.getTotalShares())
                + ",流通股:" + Utils.amountToShortUnit(mStockInfo.getOutstanding()) + "\n";
        fin_info += "总资产:" + Utils.amountToShortUnit(mStockInfo.getTotalAssets())
                + ",固定资产:" + Utils.amountToShortUnit(mStockInfo.getFixedAssets())
                + ",净资产:" + Utils.amountToShortUnit(mStockInfo.getNetAssets())
                + " 资产负债率:" + mStockInfo.getAssetDebtRatio() + "%\n";
        fin_info += "营业收入:" + Utils.amountToShortUnit(mStockInfo.getOperatingRevenue())
                + ",投资收益:" + Utils.amountToShortUnit(mStockInfo.getInvestmentIncome())
                + ",研发费用:" + Utils.amountToShortUnit(mStockInfo.getRDExpense())
                + ",收入同比:" + mStockInfo.getYearOnYearRevenue() + "%\n";
        fin_info += "营业利润:" + Utils.amountToShortUnit(mStockInfo.getOperatingProfit())
                + ",利润总额:" + Utils.amountToShortUnit(mStockInfo.getTotalProfit())
                + ",净利润:" + Utils.amountToShortUnit(mStockInfo.getNetProfit())
                + ",税后利润:" + Utils.amountToShortUnit(mStockInfo.getAfterTaxProfit())
                + ",扣非净利润:" + Utils.amountToShortUnit(mStockInfo.getNetProfitAfterDeductionNonRecurring())
                + ",未分利润:" + Utils.amountToShortUnit(mStockInfo.getUndividedProfit())
                + ",利润同比:" + mStockInfo.getYearOnYearProfit() + "%\n";
        fin_info += "净利润率:" + mStockInfo.getNetProfitRate() + "%"
                + ",营业利润率:" + mStockInfo.getOperatingProfitMargin() + "%"
                + ",净资产营收利润率:" + String.format("%.2f%%", netAssetsOperatingProfitRate)
                + ",毛利率:" + mStockInfo.getGrossProfitRate() + "%\n";
        fin_info += "总现金流:" + Utils.amountToShortUnit(mStockInfo.getTotalCashFlow())
                +",经营现金流:" + Utils.amountToShortUnit(mStockInfo.getOperatingCashFlow())
                +",每股现金流:" + mStockInfo.getNetCashFlowPerShare() + "\n";
        fin_info += "权益比:" + mStockInfo.getEquityRatio() + "%"
                +",股息率:" + mStockInfo.getDividendYieldRatio() + "%"
                +",市销率:" + mStockInfo.getPriceToSaleRatio()
                +",市现率:" + mStockInfo.getPriceToCashRatio()
                +",市净率:" + mStockInfo.getPriceToBookRatio()
                + "\n";
        return fin_info;

    }

    public void updateTodayQuote() {
        synchronized (mTodayQuoteLock) {
            updateTodayQuoteLocked();
        }
    }

    private void updateTodayQuoteLocked() {
        RealmConfiguration todayRealmConfig = new RealmConfiguration.Builder()
                .name("today_quotes.realm")
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm realm = Realm.getInstance(todayRealmConfig);
        RealmResults<TodayQuote> results = realm.where(TodayQuote.class).
                equalTo("necode", mNetEaseCode).findAll();
        if (results.size() == 1) {
            List<TodayQuote> resList = realm.copyFromRealm(results);
            mTodayQuote = resList.get(0);
        }
        realm.close();
    }

    public String price() {
        if (mTodayQuote == null) {
            return "0.0";
        } else {
            return Utils.priceToDecimalString(mTodayQuote.getPrice());
        }
    }

    public float getPrice() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return mTodayQuote.getPrice();
        }
    }

    public float getYestClose() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return  mTodayQuote.getYestclose();
        }
    }

    public float getHigh() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return mTodayQuote.getHigh();
        }
    }

    public float getLow() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return mTodayQuote.getLow();
        }
    }

    public float getOpen() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return mTodayQuote.getOpen();
        }
    }

    public float getVolume() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return mTodayQuote.getVolume();
        }
    }

    public float getAmount() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            return mTodayQuote.getTurnover();
        }
    }

    public int getIDateOfUpdate() {
        if (mTodayQuote == null) {
            return 0;
        } else {
            try {
                String updateStr = mTodayQuote.getUpdate();
                SimpleDateFormat updateFmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.CHINA);

                Date date = updateFmt.parse(updateStr);
                return Utils.getIDateFromDate(date);
            } catch (ParseException e) {
                return 0;
            }
        }
    }

    public String pricePercent() {
        if (mTodayQuote == null) {
            return "0.0";
        } else {
            return Utils.percentToDecimalString(mTodayQuote.getPercent() * 100);
        }
    }

//    String turnoverPercent() {
//        if (mTodayQuote == null || mFinanceBasics == null) {
//            return "0.0";
//        } else {
//            float turnoverPercent = mTodayQuote.getVolume() /
//                    (mFinanceBasics.getOutstanding() * 10000 * 10000);
//            return Utils.percentToDecimalString(turnoverPercent * 100);
//        }
//    }

    public float getTurnoverPercent() {
        if (mTodayQuote == null || mStockInfo == null) {
            return 0;
        } else {
            return (mTodayQuote.getVolume() * 100) /
                    (mStockInfo.getOutstanding() * 10000 * 10000);
        }
    }

    public float getNetAssetsOperatingProfitRatio() {
        if (mStockInfo == null) {
            return 0;
        } else {
            float ns = mStockInfo.getNetAssets();
            float op = mStockInfo.getOperatingProfit();
            float npo = (op * 100.0f)/ns;
            return npo;
        }
    }

    public float getPriceEarningRatio() {
        if (mStockInfo == null) {
            return 0;
        } else {
            float operateIncome = mStockInfo.getOperatingRevenue();
            float npr = mStockInfo.getNetProfitRate();
            float netProfit = (operateIncome * npr)/100.0f;
            float eps = netProfit / mStockInfo.getOutstanding();
            float price = getPrice();
            return  price / eps;
        }
    }


    @SuppressWarnings("deprecation")
    public float computePredictVolume() {
        if (mTodayQuote == null) {
            return 0;
        }
        float tradeSeconds = Utils.TRADE_SECONDS_FULL_DAY;
        try {
            String updateStr = mTodayQuote.getUpdate();
            SimpleDateFormat updateFmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.CHINA);
            Date upDate = updateFmt.parse(updateStr);
            Date amOpen = new Date(upDate.getTime());
            amOpen.setHours(9); amOpen.setMinutes(30); amOpen.setSeconds(0);
            Date amClose = new Date(upDate.getTime());
            amClose.setHours(11); amClose.setMinutes(30); amClose.setSeconds(0);
            Date pmOpen = new Date(upDate.getTime());
            pmOpen.setHours(13); pmOpen.setMinutes(0); pmOpen.setSeconds(0);
            Date pmClose = new Date(upDate.getTime());
            pmClose.setHours(15); pmClose.setMinutes(30); pmClose.setSeconds(0);

            if (upDate.getTime() >= pmClose.getTime()) {
                tradeSeconds = Utils.TRADE_SECONDS_FULL_DAY;
            } else if (upDate.getTime() > pmOpen.getTime()) {
                tradeSeconds = (upDate.getTime() - pmOpen.getTime()) / 1000.0f
                        + Utils.TRADE_SECONDS_HALF_DAY;
            } else if (upDate.getTime() >= amClose.getTime()) {
                tradeSeconds = Utils.TRADE_SECONDS_HALF_DAY;
            } else if (upDate.getTime() >= amOpen.getTime()) {
                tradeSeconds = (upDate.getTime() - amOpen.getTime()) / 1000.0f;
            }
        } catch (ParseException e) {
            tradeSeconds = Utils.TRADE_SECONDS_FULL_DAY;
        }
        float scale = Utils.TRADE_SECONDS_FULL_DAY / tradeSeconds;
        return scale * mTodayQuote.getVolume();
    }

    public String getVolToMa20Percent(float predictVolume) {
        if (mMa20Volume <= 0) {
            rebuildVolumeParams();
        }

        if (predictVolume == 0 || mMa20Volume <= 0) {
            return "0.0";
        } else {
            float vol2Ma20pct = predictVolume / mMa20Volume;
            String strVolToMa20Pct = "0.0%";
            try {
                strVolToMa20Pct = Utils.percentToDecimalString(vol2Ma20pct * 100);
            } catch (NumberFormatException e) {
                Log.e(TAG, "Fatal error, " + mName + "-" + mCode +
                                ", ma20sum=" + mMa20Volume
                                + ", predictVolume=" + predictVolume
                                + ", volPct=" + vol2Ma20pct
                        , e);
            }
            return "20:" +strVolToMa20Pct;
        }
    }

    public String getVolToLastVolumePercent(float predictVolume) {
        if (mLastHistoryTradeVolume <= 0) {
            rebuildVolumeParams();
        }

        if (predictVolume == 0 || mLastHistoryTradeVolume <= 0) {
            return "0.0";
        } else {
            float v2lv = predictVolume / mLastHistoryTradeVolume;
            String strV2LV = "0.0%";
            try {
                strV2LV = Utils.percentToDecimalString(v2lv * 100);
            } catch (NumberFormatException e) {
                Log.e(TAG, "Fatal error, " + mName + "-" + mCode +
                                ", YesterdayVolume=" + mLastHistoryTradeVolume
                                + ", predictVolume=" + predictVolume
                                + ", v2lv=" + v2lv
                        , e);
            }
            return "y:" + strV2LV;
        }
    }

    public String getVolToMa5Percent(float predictVolume) {
        if (mMa5Volume <= 0) {
            rebuildVolumeParams();
        }

        if (predictVolume == 0 || mMa5Volume <= 0) {
            return "0.0";
        } else {
            float vol2Ma5pct = predictVolume / mMa5Volume;
            String strVolToMa5Pct = "0.0%";
            try {
                strVolToMa5Pct = Utils.percentToDecimalString(vol2Ma5pct * 100);
            } catch (NumberFormatException e) {
                Log.e(TAG, "Fatal error, " + mName + "-" + mCode +
                                ", ma5sum=" + mMa5Volume
                                + ", predictVolume=" + predictVolume
                                + ", volPct=" + vol2Ma5pct
                        , e);
            }
            return "5:" + strVolToMa5Pct;
        }
    }

    public double getPercent() {
        if (mTodayQuote == null) {
            return 0.0;
        } else {
            return mTodayQuote.getPercent() * 100;
        }
    }

    public String getBuys() {
        if (mTodayQuote == null) {
            return "";
        } else {
            return mTodayQuote.getBuys();
        }
    }

    public String getSells() {
        if (mTodayQuote == null) {
            return "";
        } else {
            return mTodayQuote.getSells();
        }
    }

    public void rebuildTickQuotesFromRealm() {
        RealTimeTickChartDataSet newTickSet = new RealTimeTickChartDataSet();
        List<TickQuote> tickQuotes = Utils.getTickQuotesFromRealm(
                Utils.getTodayMinuteTickRealmFile(mNetEaseCode, Utils.getLastTradeDate()));
        if (null != tickQuotes && null != mTodayQuote) {
            newTickSet.build(tickQuotes, mTodayQuote.getYestclose());
        }
        synchronized (mTsChartDataLock) {
            mTodayMinuteTickData = newTickSet;
        }
    }

    public RealTimeTickChartDataSet getTsChartData() {
        synchronized (mTsChartDataLock) {
            return mTodayMinuteTickData;
        }
    }

    @Override
    public String toString() {
        return mName + "(" + mCode + ")";
    }

    @Override
    public int hashCode() {
        return mKeyCode;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        return  (this.hashCode() == obj.hashCode());
    }

    @Override
    public int compareTo(StockItem other) {
        if (this.hashCode() < other.hashCode()) {
            return -1;
        } else {
            return 1;
        }
    }
}


